package br.unicamp.ic.sgct.server.dominio.servicos;

import br.unicamp.ic.sgct.client.dominio.to.*;
import br.unicamp.ic.sgct.client.aplicacao.trabalho.*;
import br.unicamp.ic.sgct.client.dominio.exception.InfraException;
import br.unicamp.ic.sgct.client.dominio.to.TrabalhoTO;
import br.unicamp.ic.sgct.server.dominio.entidades.*;
import br.unicamp.ic.sgct.server.recursos.persistencia.BasicCrudDAO;
import br.unicamp.ic.sgct.server.recursos.persistencia.DAOException;

import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class TrabalhoServiceImpl extends RemoteServiceServlet implements TrabalhoService
{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	BasicCrudDAO<Trabalho, Long> dao = new BasicCrudDAO<Trabalho, Long>(Trabalho.class);
	BasicCrudDAO<Participante, Long> daoParticipante = new BasicCrudDAO<Participante, Long>(Participante.class);
    BasicCrudDAO<Avaliador, Long> daoAvaliador = new BasicCrudDAO<Avaliador, Long>(Avaliador.class);
    BasicCrudDAO<Area, Long> daoArea = new BasicCrudDAO<Area, Long>(Area.class);
    BasicCrudDAO<Avaliacao, Long> daoAvaliacao = new BasicCrudDAO<Avaliacao, Long>(Avaliacao.class);
    BasicCrudDAO<Submissao, Long> daoSubmissao = new BasicCrudDAO<Submissao, Long>(Submissao.class);

    private Set<Autor> obterAutores(List<AutorTO> autoresTO)
    {
    	Set<Autor> autores = new HashSet<Autor>();
    	
    	if(autoresTO != null)
    	{
    		for(AutorTO toau : autoresTO)
    		{
    			if(toau instanceof ParticipanteTO)
    			{
    				//Participante p = new Participante();
    				autores.add(daoParticipante.findById(toau.getId()));
    			}
    			else
    			{
    				//Avaliador a = new Avaliador();
    				autores.add(daoAvaliador.findById(toau.getId()));
    			}
    		}
    	}
    	
    	return autores;
    }
    
    private Set<Area> obterAreas(List<AreaTO> areasTO) 
    {
    	Set<Area> areas = new HashSet<Area>();
    	
    	if(areasTO != null)
    	{   	
	    	for (AreaTO area : areasTO) 
	    	{
	    		areas.add(daoArea.findById(area.getId()));
			}
    	}
    	
    	return areas;
    }
    
    private Set<Avaliacao> obterAvaliacoes(List<AvaliacaoTO> avaliacoesTO) 
    {
    	Set<Avaliacao> avaliacoes = new HashSet<Avaliacao>();
    	
    	if(avaliacoesTO != null)
    	{ 
	    	for (AvaliacaoTO avaliacao : avaliacoesTO)
	    	{
	    		avaliacoes.add(daoAvaliacao.findById(avaliacao.getId()));
			}
    	}
    	
    	return avaliacoes;
    }  
    
    private Set<Submissao> obterSubmissoes(List<SubmissaoTO> submissoesTO) 
    {
    	Set<Submissao> submissoes = new HashSet<Submissao>();
    	
    	if (submissoesTO != null) 
    	{
    		for (SubmissaoTO submissaoTO : submissoesTO) 
    		{
    			if (submissaoTO.getId() != null) 
    			{
    				submissoes.add(daoSubmissao.findById(submissaoTO.getId()));
    			}
    		}
    	}
    	
    	return submissoes;
    }
    
	private String obterNomeArquivo(String nomeArquivoSub) 
	{
		String nomeArq = nomeArquivoSub;
		
		if (nomeArquivoSub != null) 
		{
			if (nomeArquivoSub.contains("\\")) 
			{
				int indexInit = nomeArquivoSub.lastIndexOf('\\') + 1;
				
				if (indexInit > nomeArquivoSub.length() ) 
				{
					nomeArq = nomeArquivoSub.substring(indexInit, nomeArquivoSub.length() - 1);
				}
			}
			else 
			{
				if (nomeArquivoSub.contains("/")) 
				{
					int indexInit = nomeArquivoSub.lastIndexOf('/') + 1;
					
					if (indexInit > nomeArquivoSub.length()) 
					{
						nomeArq = nomeArquivoSub.substring(indexInit, nomeArquivoSub.length() - 1);
					}
				}
			}
		}
		
		return nomeArq;
	}
	
	private Submissao criarNovaSubmissao(String nomeArq) 
	{
		Submissao submissao = new Submissao(nomeArq, new Date());
		return submissao;
	}
	
	@Override
	public TrabalhoTO submeterTrabalho(TrabalhoTO to) throws InfraException, Exception 
	{
		Trabalho trabalhoGravado = null;
		
		if (to.getIdTrabalho() == null) 
		{
			trabalhoGravado = gravarNovoTrabalho(to);
		}
		else
		{
			trabalhoGravado = atualizarTrabalho(to);
		}
		
		return trabalhoGravado.getTo();
	}


	private Trabalho atualizarTrabalho(TrabalhoTO to) throws InfraException, Exception 
	{
		Trabalho tra = null;
		tra = dao.findById(to.getIdTrabalho());
		tra.setAutores(obterAutores(to.getAutores()));
		tra.setAreas(obterAreas(to.getAreas()));
		tra.setAvaliacoes(obterAvaliacoes(to.getAvaliacoes()));
		tra.setSubmissoes(obterSubmissoes(to.getSubmissoes()));		
		String nomeArq = obterNomeArquivo(to.getNomeArquivo());
		
		try
		{
			dao.beginTransaction();
			if (nomeArq != null)
			{
				Submissao submissao = criarNovaSubmissao(nomeArq);
				submissao.setTrabalho(tra);
				tra.getSubmissoes().add(submissao);
			}
			tra = dao.update(tra);
			dao.commitTransaction();
		}
		catch(DAOException e)
		{
			dao.rollbackTransaction();
			e.printStackTrace();
			throw e;
		}
		
		return tra;
	}


	private Trabalho gravarNovoTrabalho(TrabalhoTO to) throws InfraException, Exception 
	{
		Set<Autor> autores = obterAutores(to.getAutores());
		Set<Area> areas = obterAreas(to.getAreas());
		Set<Avaliacao> avaliacoes = obterAvaliacoes(to.getAvaliacoes());
		Set<Submissao> submissoes = obterSubmissoes(to.getSubmissoes());
		String nomeArq = obterNomeArquivo(to.getNomeArquivo());
		Trabalho tra = null;
		try
		{
			dao.beginTransaction();
			tra = dao.create(new Trabalho(to.getTitulo(), to.getResumo(), to.getTipo(), to.getConferencia(), autores, areas, avaliacoes));
			if (nomeArq != null)
			{
				Submissao submissao = criarNovaSubmissao(nomeArq);
				submissao.setTrabalho(tra);
				submissoes.add(submissao);
			}
			tra.setSubmissoes(submissoes);
			tra = dao.update(tra);
			dao.commitTransaction();
		}
		catch(DAOException e)
		{
			dao.rollbackTransaction();
			e.printStackTrace();
			throw e;
		}
		
		return tra;
	}
}
